dbt snapshots 是 dbt 提供的一種備份機制,記錄隨時間變化的 table 情況
就 migo data 團隊使用 snapshot 有兩個目的:
dbt 的 snapshot 機制為來源 table type-2 Slowly Changing Dimensions (或稱 SCDs)*,用於識別 table 中的 row 如何隨時間變化。 *SCD 的定義
以下寫在 snapshot sql 檔內,以 member_snapshot.sql 為例
範例
---1---
{% snapshot member_snapshot %}
------2------
{{
config(
target_database='migocorp-2103',
target_schema='snapshots',
unique_key='MemberID',
strategy='timestamp',
updated_at='UpdateDate'
)
}}
----3-----
select * from {{ source('jaffle_shop', 'orders') }}
{% endsnapshot %}
target_database, target_schema 不特別說,就是你的 snapshot 要放的 database 和 schema 地方以下介紹其他三項:
strategy:你一開始要決定要用什麼 snapshot 策略
最常用的是 timestamp, check 兩個
updated_at
欄位來判斷一行資料是否有變動。如果某 row 資料的 updated_at
欄位比上次執行 snapshot 的時間更晚,dbt 將會使舊的記錄失效並記錄新的資料。如果時間戳沒有變化,那麼 dbt 將不會採取任何行動。如果你的 table 有 updated_at 的欄位記錄資料更新時間,這是 dbt snapshot 優先建議的策略updated_at
欄位的 table,dbt 建議使用 check 策略。這種策略是透過比較check_cols 欄位資料有無變動來判斷。如果這些欄位中的任何一個有變化,那麼 dbt 將會使舊的記錄失效並記錄新的資料。如果欄位值相同,那麼 dbt 將不會採取任何行動{% snapshot orders_snapshot_check %}
{{
config(
target_schema='snapshots',
strategy='check',
unique_key='id',
check_cols=['status', 'is_cancelled'],
)
}}
select * from {{ source('jaffle_shop', 'orders') }}
{% endsnapshot %}
{% snapshot transaction_items_snapshot %}
{{
config(
unique_key="transaction_id||'-'||line_item_id",
...
)
}}
select
transaction_id||'-'||line_item_id as id,
*
from {{ source('erp', 'transactions') }}
{% endsnapshot %}
使用 timestamp 策略則需要填此項目,dbt 用此時間欄位判斷資料無更新以記錄資料
check_cols
用 check 策略則需要填此項目,只要填入欄位值與原本有差異都會紀錄
你的 table 會多4個欄位
欄位 | 解釋 | 用法 |
---|---|---|
dbt_valid_from | snapshot row 被 insert 的時間 | 透過 dbt_valid_from 看該欄位的不同時間版本 |
dbt_valid_to | 若該 row 已有新紀錄,則舊的 row 變成無效的時間 | 可以當作 row 的有效期限日,假如是最新的 row 則是 null. |
dbt_scd_id | 每個 snapshot 紀錄的 unique key | dbt 內部邏輯判斷使用 |
dbt_updated_at | 該 row 更新時間 | dbt 內部邏輯判斷使用 |
若你有很多 table 須設定 snapshot,在每個 model 內設定 config 是比較難管理的,因此你可以參考過去說的 dbt 架構設計,在 dbt_project.yml 管理每個 table snapshot 的設定,如下範例
snapshots:
migocorp:
datamart:
Member_snapshot:
+unique_key: MemberID
+strategy: timestamp
+updated_at: UpdateDate
ref
,而不是用 source 喔!-- models/changed_orders.sql
select * from {{ ref('orders_snapshot') }}
snapshot 來源 table 欄位有變動怎麼處理
key 值有重複會發生什麼事?
若你的 key 值有重複,可能導致結果誤差,且 dbt 不會幫你檢查。因此建議來源 table 多做 unique 檢查
如果你的 snapshot 來源 table 刪除 row, dbt 怎麼處理?
dbt 預設刪掉的 row 是正常的,你若要挑出來需設定 invalidate_hard_deletes=True,則 dbt 會把 snapshot table 的 dbt_valid_to 欄位設為現在時間
越寫越覺得 dbt snapshot 的水很深,還有其他注意事項請來官方查看